﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Records;
using Orchard.Data;
using SchoolPointe.RelatedContent.Models;
using SchoolPointe.RelatedContent.Settings;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.Logging;

namespace SchoolPointe.RelatedContent.Services
{
    public class RelatedContentService : IRelatedContentService
    {
        private readonly IContentManager _contentManager;
        private readonly IContentDefinitionManager _contentDefinitionManager;
        private readonly IRepository<RelatedContentItemPartRecord> _relatedContentItemRepo;

        public RelatedContentService(IContentManager contentManager, IContentDefinitionManager contentDefinitionManager, IRepository<RelatedContentItemPartRecord> relatedContentItemRepo)
        {
            _contentManager = contentManager;
            _contentDefinitionManager = contentDefinitionManager;
            _relatedContentItemRepo = relatedContentItemRepo;
        }
      
        public void SetRelatedItems(RelatedContentPart relatedContent, string relationshipIdentifier, List<int> contentItemIDs)
        {
            //query for existing relationships
            var existingRelationships =
                _relatedContentItemRepo.Fetch(
                    rc =>
                    rc.RelationshipIdentifier == relationshipIdentifier &&
                    rc.RelatedContentPartRecord == relatedContent.Record);

            //this shouldn't be necessary, but check anyway
            contentItemIDs = contentItemIDs.Distinct().ToList();

            var existingRelationshipIds = existingRelationships.Select(er => er.RelatedItem.Id).ToList();

            //skip existing items
            foreach (var contentItemId in contentItemIDs.Where(id => !existingRelationshipIds.Contains(id)))
            {
                var relatedContentItem = new RelatedContentItemPartRecord();
                relatedContentItem.RelatedItem = _contentManager.Get(contentItemId).Record;
                relatedContentItem.RelatedContentPartRecord = relatedContent.Record;
                relatedContentItem.RelationshipIdentifier = relationshipIdentifier;
                _relatedContentItemRepo.Create(relatedContentItem);
                relatedContent.RelatedItems.Value.Add(relatedContentItem);
            }

            //delete items that are no longer related
            foreach (var removedItemId in existingRelationshipIds.Where(er => !contentItemIDs.Contains(er)))
            {
                var relatedItem = existingRelationships.Single(er => er.RelatedItem.Id == removedItemId);
                relatedContent.RelatedItems.Value.Remove(relatedItem);
                _relatedContentItemRepo.Delete(relatedItem);                
            }
        }

        public void AddRelatedItem(RelatedContentPart relatedContent, string relationshipIdentifier, ContentItem contentItem)
        {
            if (relatedContent.RelatedItems.Value == null)
                relatedContent.RelatedItems.Value = new List<RelatedContentItemPartRecord>();

            if (!relatedContent.RelatedItems.Value.Any(ri => ri.RelationshipIdentifier == relationshipIdentifier && ri.RelatedItem == contentItem.Record))
            {
                var relatedContentItem = new RelatedContentItemPartRecord();
                relatedContentItem.RelatedItem = contentItem.Record;
                relatedContentItem.RelatedContentPartRecord = relatedContent.Record;
                relatedContentItem.RelationshipIdentifier = relationshipIdentifier;
                _relatedContentItemRepo.Create(relatedContentItem);
                relatedContent.RelatedItems.Value.Add(relatedContentItem);
            }

        }

        public void AddTemporaryRelatedItem(RelatedContentPart relatedContent, string relationshipIdentifier, ContentIdentity relatedIdentity)
        {
            if (relatedContent.RelatedItems.Value == null)
                relatedContent.RelatedItems.Value = new List<RelatedContentItemPartRecord>();

            //TODO: Check for existing relationship
            //if (!relatedContent.RelatedItems.Value.Any(ri => ri.RelationshipIdentifier == relationshipIdentifier && ri.RelatedItem == contentItem.Record))
            //{
                var relatedContentItem = new RelatedContentItemPartRecord();
                relatedContentItem.RelatedItemIdentifier = relatedIdentity.ToString();
                relatedContentItem.RelatedContentPartRecord = relatedContent.Record;
                relatedContentItem.RelationshipIdentifier = relationshipIdentifier;
                _relatedContentItemRepo.Create(relatedContentItem);
                relatedContent.RelatedItems.Value.Add(relatedContentItem);
            //}
        }

        public IEnumerable<ContentItemRecord> GetRelatedItems(RelatedContentPart part, string relationshipIdentifier)
        {
            var settings = new RelatedContentPartSettings(part.TypePartDefinition.Settings);
            var relationship = settings.Relationships.Single(r => r.Identifier == relationshipIdentifier);

            return GetRelatedItems(part, relationship);
        }

        public IEnumerable<ContentItemRecord> GetRelatedItems(RelatedContentPart part, RelatedContentRelationship relationship)
        {
            IEnumerable<ContentItemRecord> relatedItems;
            if (part.RelatedItems.Value != null)
            {
                if (string.IsNullOrEmpty(relationship.InverseOf))
                    relatedItems = part.RelatedItems.Value
                        .Where(ri => ri.RelationshipIdentifier == relationship.Identifier && ri.RelatedContentPartRecord == part.Record)
                        .Select(ri => ri.RelatedItem);
                else
                {
                    var contentType = relationship.InverseOf.Split('.')[0];
                    var identifier = relationship.InverseOf.Split('.')[1];
                    relatedItems = part.RelatedItems.Value.Where(ri =>
                            ri.RelationshipIdentifier == identifier &&
                            ri.RelatedContentPartRecord.ContentItemRecord.ContentType.Name == contentType && 
                            ri.RelatedItem == part.ContentItem.Record)
                        .Select(ri => ri.RelatedContentPartRecord.ContentItemRecord);
                }
            }
            else
                relatedItems = new List<ContentItemRecord>();
            return relatedItems;
        }
    }
}